package net.lzzy.practices.services;

import net.lzzy.practices.entities.Applicant;

import net.lzzy.practices.entities.Course;
import net.lzzy.practices.entities.User;
import net.lzzy.practices.repositories.ApplicantRepository;
import net.lzzy.practices.repositories.CourseRepository;
import net.lzzy.practices.repositories.UserRepository;
import net.lzzy.practices.utils.JwtUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

@Service
public class ApplicantServiceImpl implements ApplicantService{
    private final ApplicantRepository repository;
    private final CourseRepository cRepository;
    private final UserRepository uRepository;

    @Autowired
    public ApplicantServiceImpl(ApplicantRepository repository, CourseRepository cRepository, UserRepository uRepository) {
        this.repository = repository;
        this.cRepository = cRepository;
        this.uRepository = uRepository;
    }

    @Override
    public Applicant apply(UUID studentId, UUID courseId, String token) {
        if(!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        User student=uRepository.findById(studentId).orElse(null);
        if(student==null){
            return null;
        }
        Course course=cRepository.findById(courseId).orElse(null);
        if (course==null){
            return null;
        }
        Applicant applicant=new Applicant();
        applicant.setStudent(student);
        applicant.setCourse(course);
        applicant.setStatus(Applicant.STATUS_APPLYING);
        return repository.save(applicant);
    }

    @Override
    public List<Applicant> getAllCourses(UUID studentId, String token) {
        if(!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsOrderByApplyTimeDesc(studentId);
    }

    @Override
    public List<Applicant> getEnrolledCourses(UUID studentId, String token) {
        if(!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_APPROVED);
    }

    @Override
    public List<Applicant> getApplyingCourses(UUID studentId, String token) {
        if(!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_APPLYING);
    }

    @Override
    public List<Applicant> getDeclinedCourses(UUID studentId, String token) {
        if(!studentId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.STATUS_REJECTED);
    }

    public Applicant update(UUID applicantId,String token,int status){
        Applicant applicant=repository.findById(applicantId).orElse(null);
        if(applicant==null){
            return null;
        }
        Course course = applicant.getCourse().getCourse();
        UUID teacherId=course.getTeacher().getId();
        if(!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        applicant.setStatus(status);
        return repository.save(applicant);
    }
    @org.springframework.transaction.annotation.Transactional(rollbackFor = Exception.class)
    @Override
    public Applicant approve(UUID applicantId, String token) {
        Applicant applicant= update(applicantId,token,Applicant.STATUS_APPROVED);
        if (applicant!=null){
            Course course = applicant.getCourse();
            User student=applicant.getStudent();
            List<User> students=course.getStudents();
            if(!students.contains(student)){
                students.add(student);
            }
            course.setStudents(students);
            applicant.setCourse(cRepository.save(course));
        }
        return applicant;
    }

    @Override
    public Applicant decline(UUID applicantId, String token) {
        return update(applicantId,token,Applicant.STATUS_APPROVED);
    }

    private List<Applicant> getStudent(UUID courseId,String token,int status){
        Course course = cRepository.findById(courseId).orElse(null);
        if(course==null){
            return null;
        }
        UUID teacherId=course.getTeacher().getId();
        if (!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        return repository.findApplicantsByCourseIdEqualsAndStatusEqualsOrderByApplyTimeDesc(courseId,status);
    }
    @Override
    public List<Applicant> getEnrolledStudents(UUID courseId, String token) {
        return getStudent(courseId,token,Applicant.STATUS_APPROVED);
    }

    @Override
    public List<Applicant> getApplyingStudents(UUID courseId, String token) {
        return getStudent(courseId,token,Applicant.STATUS_APPLYING);
    }

    @Override
    public List<Applicant> getDeclinedStudents(UUID courseId, String token) {
        return getStudent(courseId,token,Applicant.STATUS_REJECTED);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Course removeStudent(UUID courseId, UUID studentId, String token) {
        Course course = cRepository.findById(courseId).orElse(null);
        if(course==null){
            return null;
        }

        UUID teacherId=course.getTeacher().getId();
        if(!teacherId.toString().equals(JwtUtil.verifyToken(token))){
            return null;
        }
        course.getStudents().removeIf(s->s.getId().equals(studentId));
        Applicant applicant= repository.findApplicantByCourseIdAndStudentId(courseId,studentId);
        if(applicant!=null){
            applicant.setStatus(Applicant.STATUS_REJECTED);
            repository.save(applicant);
        }
        return cRepository.save(course);
    }
}